package com.flute.haflute.agent.job;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TreeSet;

import com.flute.haflute.agent.topo.Node;
import com.flute.haflute.exception.NoNodeAvailableException;
import com.flute.haflute.jobbox.base.CloudJobConf;
import com.flute.haflute.jobbox.common.CloudContext;
import com.flute.haflute.monitor.JobMonitorInfo;
import com.flute.haflute.tools.SerializeHistroyJob;

/**
 * 一个JOB工作上下文策略生成器，系统启动没有配置相关策略的时候，默认使用该策略<br>
 * 
 * 该策略使用一下方式进行任务资源的调度：<br>
 * 
 * 1. 选取随机数目的节点 <br>
 * 2. 选取其中一个任意节点为主控节点<br>
 * 3. 其他节点为执行任务的从节点
 * 
 */
public class RandomAwareOfHistoryStrategy implements JobContextStrategy {
	
	private Random rand = new Random();

	/*
	 * @see
	 * com.flute.haflute.agent.job.JobContextStrategy#getJobContext(com.flute
	 * .haflute.agent.job.JobRequest)
	 */
	@Override
	public JobContext getJobContext(CloudJobConf request)
			throws NoNodeAvailableException {
		List<Node> nodes = JobResourceManager.getInstance().getAllFreeNodes();
		JobContext jobContext = null;
		if (nodes.size() == 0) {
			jobContext = getBusyJobContextWithCapacity(request);
			if (jobContext == null) {
				throw new NoNodeAvailableException();
			}
			return jobContext;
		}
		int numNodes = nodes.size();
		int realSize = request.getTasksNeeded();
		realSize = (realSize > numNodes) ? numNodes : realSize;
		realSize = (realSize <= 0) ? rand.nextInt(numNodes) + 1 : realSize;

		jobContext = getJobContextByHistoryContext(request.getJobDescription(),
				nodes);
		if (jobContext != null) {
			return jobContext;
		}

		jobContext = new JobContext();
		jobContext.incJobCount();
		ArrayList<Node> slaves = new ArrayList<Node>(realSize);
		jobContext.setJobMaster(nodes.get(realSize - 1));

		for (int i = 0; i < realSize; i++) {
			slaves.add(nodes.get(i));
		}
		jobContext.setJobSlaves(slaves);

		return jobContext;
	}

	private JobContext getBusyJobContextWithCapacity(CloudJobConf request) {
		List<JobContext> contexts = JobResourceManager.getInstance()
				.getBusyJobContext();
		if (contexts.size() == 0)
			return null;

		// if need nodes
		int tasksNeeded = request.getTasksNeeded();
		if (tasksNeeded < 1) {
			JobContext context = contexts.get(0);
			context.incJobCount();
			return context;
		} else {
			for (JobContext context : contexts) {
				if (context.getJobSlaves().size() == tasksNeeded) {
					context.incJobCount();
					return context;
				}
			}

			if (request.getScalable()) {
				JobContext context = contexts.get(0);
				context.incJobCount();
				return context;
			}
		}

		return null;
	}

	private JobContext getJobContextByHistoryContext(String jobDescription,
			List<Node> freeNodes) {
		/**
		 * 用JOB信息的描述与历史的JOB比较 如果发现相同的 就选择历史任务使用的节点
		 */
		if (jobDescription == null) {
			return null;
		}

		JobContext jobContext = null;
		List<JobMonitorInfo> list = getHistoryjobs();

		if (list == null) {
			return null;
		}

		JobMonitorInfo lastSamejobMinfo = null;
		for (JobMonitorInfo joMbinfo : list) {
			if (joMbinfo.getJobDescription() != null
					&& joMbinfo.getJobDescription().equals(jobDescription)) {
				// 取最后一个进入列表的JOBMINFO对象
				lastSamejobMinfo = joMbinfo;
			}
		}

		ArrayList<Node> slaves = new ArrayList<Node>(freeNodes.size());
		if (lastSamejobMinfo != null) {
			TreeSet<String> set = new TreeSet<String>();
			Node master = lastSamejobMinfo.getMaster();
			List<String> childs = lastSamejobMinfo.getChilds();
			for (String str : childs) {
				set.add(CloudContext.getIpFromChildName(str));
			}

			// 从空闲节点中取出所有原Slave节点
			for (Node node : freeNodes) {
				if (set.contains(node.getIp())) {
					slaves.add(node);
				}
			}

			if (freeNodes.contains(master)) {
				jobContext = new JobContext();
				jobContext.setJobMaster(master);
				if (slaves.size() == 0) {
					slaves.add(master);
				}
				jobContext.setJobSlaves(slaves);
			} else if (slaves.size() > 0) {
				jobContext = new JobContext();
				jobContext.setJobMaster(slaves.get(0));
				jobContext.setJobSlaves(slaves);
			}
		}

		jobContext.incJobCount();
		return jobContext;
	}

	@SuppressWarnings("unchecked")
	private List<JobMonitorInfo> getHistoryjobs() {
		List<JobMonitorInfo> list = null;
		SerializeHistroyJob serializeobj = new SerializeHistroyJob(null);
		Object obj = serializeobj.uncoilSerializeObj();
		if (obj instanceof List) {
			list = (List<JobMonitorInfo>) obj;
		}
		serializeobj = null;
		return list;
	}

}
